﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
using Box2DX.Common;
using System.Windows.Interactivity;


namespace Expression.Samples.Physics.Behaviors {
	public class Magnet: Behavior<FrameworkElement> {

		public static readonly DependencyProperty MagnetismProperty = DependencyProperty.Register("Magnetism", typeof(double), typeof(Magnet), new PropertyMetadata(.1));
		public static readonly DependencyProperty FallOffProperty = DependencyProperty.Register("FallOff", typeof(double), typeof(Magnet), new PropertyMetadata(1.2));
		public static readonly DependencyProperty MaxDistanceProperty = DependencyProperty.Register("MaxDistance", typeof(double), typeof(Magnet), new PropertyMetadata(2.5));

		private static List<Magnet> worldMagnets = new List<Magnet>();
		private Entity entity;


		public Magnet() {
		}

		public double Magnetism {
			get { return (double)this.GetValue(Magnet.MagnetismProperty); }
			set { this.SetValue(Magnet.MagnetismProperty, value); }
		}

		public double FallOff {
			get { return (double)this.GetValue(Magnet.FallOffProperty); }
			set { this.SetValue(Magnet.FallOffProperty, value); }
		}

		public double MaxDistance {
			get { return (double)this.GetValue(Magnet.MaxDistanceProperty); }
			set { this.SetValue(Magnet.MaxDistanceProperty, value); }
		}

		protected override void OnAttached() {
			base.OnAttached();

			this.Dispatcher.BeginInvoke(delegate {
				this.entity = Entity.GetElementEntity(this.AssociatedObject);

				if (this.entity != null) {

					Magnet.worldMagnets.Add(this);

					CompositionTarget.Rendering += this.HandleTick;
				}
			});
		}

		protected override void OnDetaching() {
			base.OnDetaching();


			if (this.entity != null) {
				CompositionTarget.Rendering -= this.HandleTick;

				Magnet.worldMagnets.Remove(this);
			}
		}

		private void HandleTick(object sender, EventArgs e) {

			foreach (Magnet other in worldMagnets) {

				if (other != this) {
					Vector force = other.entity.BodyPosition - this.entity.BodyPosition;

					if (force.Length < (this.MaxDistance + other.MaxDistance)) {

						force = 5000 * force * (1 / System.Math.Pow(force.LengthSquared, this.FallOff + other.FallOff)) * (this.Magnetism + other.Magnetism);

						this.entity.Body.ApplyForce(force, other.entity.BodyPosition);
					}
				}
			}
		}
	}
}
